<?php

use Carbon\Carbon;
use App\Models\User;
use Ramsey\Uuid\Uuid;
use App\Models\Config;
use App\Models\ConfigApp;
use Brick\Math\BigDecimal;
use App\Models\ConfigSale;
use App\Models\ProductSku;
use App\Models\ConfigStorm;
use Illuminate\Support\Str;
use App\Models\ConfigWithdraw;
use App\Supports\Payment\PayInit;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Model;
use App\Services\Account\AccountGoldCoins;
use App\Services\Account\AccountGoldBeans;
use App\Services\Account\AccountVipCards;
use App\Services\Account\AccountApples;
use App\Services\Account\AccountGoldCashes;
use App\Services\Account\AccountGoldSubsidies;
use App\Services\Account\AccountBalances;
use App\Services\Account\AccountRewards;
use App\Services\Account\AccountGroupCards;
use App\Supports\Payment\Contracts\PayBinder;
use Illuminate\Validation\ValidationException;

if (! function_exists('log_debug')) {
	function log_debug($message = null, $result = null) {
		Log::debug("===== {$message} \n\n ---------- [ Result ] ---------- \n\n {$result} \n\n\n");
	}
}

if (! function_exists('log_info')) {
	function log_info($message = null, $result = null) {
		Log::info("===== {$message} \n\n ---------- [ Result ] ---------- \n\n {$result} \n\n\n");
	}
}

if (! function_exists('fail')) {
	function fail($message) {
		throw ValidationException::withMessages(['err' => $message]);
	}
}

if (! function_exists('failed')) {
	function failed($message) {
		Log::error($message);
		return false;
	}
}

if (! function_exists('account_coins')) {
	/**
	 * @param User $user
	 * @return AccountGoldCoins
	 */
	function account_coins(User $user): AccountGoldCoins {
        return new AccountGoldCoins($user);
	}
}

if (! function_exists('account_beans')) {
	/**
	 * @param User $user
	 * @return AccountGoldBeans
	 */
	function account_beans(User $user): AccountGoldBeans {
        return new AccountGoldBeans($user);
	}
}

if (! function_exists('account_apples')) {
	/**
	 * @param User $user
	 * @return AccountGoldCoins
	 */
	function account_apples(User $user): AccountApples {
        return new AccountApples($user);
	}
}

if (! function_exists('account_balances')) {
	/**
	 * @param User $user
	 * @return AccountGoldCoins
	 */
	function account_balances(User $user): AccountBalances {
        return new AccountBalances($user);
	}
}

if (! function_exists('account_cards')) {
	/**
	 * @param User $user
	 * @return AccountGoldBeans
	 */
	function account_cards(User $user): AccountVipCards {
        return new AccountVipCards($user);
	}
}

if (! function_exists('account_cashes')) {
	/**
	 * @param User $user
	 * @return AccountGoldCashes
	 */
	function account_cashes(User $user): AccountGoldCashes {
        return new AccountGoldCashes($user);
	}
}

if (! function_exists('account_subsidies')) {
	/**
	 * @param User $user
	 * @return AccountGoldSubsidies
	 */
	function account_subsidies(User $user): AccountGoldSubsidies {
        return new AccountGoldSubsidies($user);
	}
}

if (! function_exists('account_rewards')) {
	/**
	 * @param User $user
	 * @return AccountRewards
	 */
	function account_rewards(User $user): AccountRewards {
        return new AccountRewards($user);
	}
}

if (! function_exists('account_group_cards')) {
	/**
	 * @param User $user
	 * @return AccountRewards
	 */
	function account_group_cards(User $user): AccountGroupCards {
        return new AccountGroupCards($user);
	}
}


if (! function_exists('cashier')) {
	/**
	 * @param $channel
	 * @return PayInit
	 */
	function cashier($channel) {
		return app(PayInit::class, ['name' => $channel]);
	}
}

if (! function_exists('cs')) {
	/**
	 * @param null $name
	 * @return Config|ConfigApp|ConfigSale|ConfigWithdraw|ConfigStorm|null
	 */
	function cs($name = null) {
		if ($name) {
			$name = '\App\Models\Config'.ucfirst(Str::camel(Str::snake($name)));
			return $name::first();
		}
		return App\Models\Config::first();
	}
}

if (! function_exists('sc')) {
	function sc($item) {
		/**
		 * Gold Storm Configs
		 */
		$configStorm = ConfigStorm::cache();
		if (isset($configStorm[$item])) {
			return $configStorm[$item];
		}
		return null;
	}
}

if (! function_exists('sms_code')) {
	function sms_code() {
		return str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);
	}
}

if (! function_exists('has_child')) {
	function has_child(Model $model, $children) {
		return $model->$children()->exists();
	}
}

if (! function_exists('big_decimal')) {
	function big_decimal($money) {
		$money = $money instanceof BigDecimal ? (string)$money : $money;
		$money = BigDecimal::of($money);
		return $money;
	}
}

if (! function_exists('oss')) {
	function oss($path) {
		return "https://littleshop.oss-cn-beijing.aliyuncs.com/{$path}";
	}
}

if (! function_exists('serial_uuid')) {
	function serial_uuid($model = null, $field = 'number') {
		$uuid = null;
		// random uuid for model.
		if ($model instanceof Model) {
			do {
				$uuid = Uuid::uuid4()->getHex();
			} while ($model->where($field, $uuid)->exists());
			return $uuid;
		}
		// random uuid only.
		return Uuid::uuid4()->getHex();
	}
}

if (! function_exists('random_number')) {
	function random_number($length = 10, $model = null, $field = null) {
		if ($length <= 0) {return null;}
		// random number for model.
		if ($model instanceof Model and $field) {
			do {
				$number = str_pad(random_int(1, str_repeat(9, $length)), $length, 0, STR_PAD_LEFT);
			} while ($model->where($field, $number)->exists());
			return $number;
		}
		// random number only.
		return str_pad(random_int(1, str_repeat(9, $length)), $length, 0, STR_PAD_LEFT);
	}
}

if (! function_exists('serial_number')) {
	function serial_number($length = 6, $model = null, $field = null) {
		if ($length <= 0) {return null;}
		$prefix = date('YmdHis'); $number = null;
		// serial number for model.
		if ($model instanceof Model and $field) {
			do {
				$number = str_pad(random_int(1, str_repeat(9, $length)), $length, 0, STR_PAD_LEFT);
			} while ($model->where($field, $number)->exists());
			return $prefix.$number;
		}
		// serial number only.
		return $prefix.str_pad(random_int(1, str_repeat(9, $length)), $length, 0, STR_PAD_LEFT);
	}
}

if (! function_exists('img_product_path')) {
	function img_product_path($path, $default = null) {
		try {

			$fileNameArr = explode('/',$path);

			$fileName = end($fileNameArr);

			//return Storage::url($path);
			if (Str::startsWith($path, ['http://', 'https://'])) {
				return $path;
			} elseif (file_exists(public_path('app')."/".$fileName)) {
				return Storage::disk('public')->url($fileName);

			} elseif (Storage::exists($path)) {

				
				return env('APP_URL')."alioss?url=".base64_encode($path);
				//return Storage::url($path);
			} elseif ($default) {
				return $default;
			}  else {
				return '';
			}
		} catch (Exception $e) {
			Log::error("Ali oss loading failed...");
			return '';
		}
	}
}

if (! function_exists('img_path')) {
	function img_path($path, $default = null) {
		try {

			$fileNameArr = explode('/',$path);

			$fileName = end($fileNameArr);
			//return Storage::url($path);
			if (Str::startsWith($path, ['http://', 'https://'])) {
				return $path;
			/*} elseif (file_exists(public_path('app')."/".$fileName)) {
				return Storage::disk('public')->url($fileName);*/
			} elseif (Storage::exists($path)) {
				//return env('APP_URL')."alioss?url=".base64_encode($path);
				return Storage::url($path);
			} elseif ($default) {
				return $default;
			}  else {
				return '';
			}
		} catch (Exception $e) {
			Log::error("Ali oss loading failed...");
			return '';
		}
	}
}

if (! function_exists('sku_from_attr')) {
	function sku_from_attr(string $attrValueIndex) {
		$arr = explode('-', $attrValueIndex);
		sort($arr); $indexString = implode('-', $arr);
		return ProductSku::where('attr_value_index', $indexString)->first();
	}
}

if (! function_exists('time_to_carbon')) {
	/**
	 * @param string $datetime
	 * @return Carbon
	 */
	function time_to_carbon(string $datetime) {
		/**
		 * Time format: 0000-00-00 00:00:00
		 */
		$origin = collect(explode(' ', $datetime));
		$date = $origin->first();
		$time = $origin->last();

		$dateArr = explode('-', $date);
		$timeArr = explode(':', $time);

		return Carbon::create($dateArr[0], $dateArr[1], $dateArr[2], $timeArr[0], $timeArr[1], $timeArr[2]);
	}
}

if (! function_exists('hide_word')) {
	function hide_word($word) {
		$wordString = Str::substr($word, 0, 1);
		$hiddenWord = Str::padRight($wordString, 6, '*');
		return $hiddenWord;
	}
}

if (! function_exists('cache_time')) {
	function cache_time() {
		$env = app()->environment();
		if ($env == 'local') {
			return 20;
		} elseif ($env == 'development') {
			return 60*60*24;
		} else {
			return random_int(60*60*30, 60*60*50);
		}
	}
}

if (! function_exists('express_code')) {
	function express_code($nameOrCode) {
		$companies = config('express.companies');
		foreach ($companies as $code => $name) {
			if (empty($code)) continue;
			if ($code == $nameOrCode) {
				return $code;
			}
			if ($name == $nameOrCode) {
				return $code;
			}
		}
		return '';
	}
}

if (! function_exists('header_sign')) {
    function header_sign(): string {
        $date = explode('-', Carbon::today()->format('Y-m-d'));
        $signNumber = ($date[0]+$date[1]*2+$date[2]*3)*2;
        return base64_encode($signNumber);
    }
}

if (! function_exists('is_request_valid')) {
    function is_request_valid(): bool {

        if (app()->environment('local')) return true;

        $sign = base64_decode(request()->headers->get('sign'));
        if (empty($sign)) return false;

        $signNumber = base64_decode(header_sign());
        if ($sign != $signNumber) return false;

        $all = request()->all();
        foreach ($all as $key => $value) {
            if (! in_array($key, config('site.request.queries'))) {
                Log::info("Invalid request query name: ({$key}).");
                return false;
            }
            if (Str::length($key) > 20) {
                Log::info("Invalid request query name length: ({$key}).");
                return false;
            }
            foreach (config('site.request.denied_values') as $deniedText) {

                $encodeValue = trim(json_encode($value), "'\"");
                if (Str::contains($encodeValue, $deniedText)
                    and !in_array($encodeValue, config('site.request.allowed_values'))) {
                    Log::info("Invalid request query denied: ({$encodeValue}|{$deniedText}).");
                    return false;
                }
                /*if (Str::length($encodeValue) > 150) {
                    Log::info("Invalid request query value length: ({$encodeValue}).");
                    return false;
                }*/
            }
        }
        return true;
    }
}

if (! function_exists('is_request_invalid')) {
    function is_request_invalid(): bool {
        return !is_request_valid();
    }
}

if (! function_exists('need_paycode')) {
    function need_paycode(User $user) {
        if (empty($user->pay_code)) {
            fail('请先设置交易密码');
        } elseif (empty(request('pay_code'))) {
            fail('请输入交易密码');
        }
    }
}

if (! function_exists('array_string')) {
    function array_string($array) {
        return str_replace(',', "\n", trim(json_encode($array), '{}'));
    }
}
